#include "centralController.h"
#include "command.h"
#include "Args.h"
#include <QPainter>
#include <QFileDialog>
#include <QMessageBox>
const DisplayNode* centralController::GetObjectByPath(nodePath path)
{
   for (int i=0;i!=path.path.count();i++)
		this->dataManipulator->EnterIntoChild(path.path[i]);
	const DisplayNode* tm=this->dataManipulator->CurrentPt();
	return tm;
}
bool centralController::ExistAvaliableProject()
{
	return this->dataManipulator->IsOpened();
}
const QPointF centralController::GetLControlPoint(int objectIndex,int index)
{
	this->dataManipulator->EnterIntoChild(objectIndex);
	const QPointF t=this->dataManipulator->LControlPointAt(index);
	this->dataManipulator->EscapeToParent();
	return t;
}
const QPointF centralController::GetRControlPoint(int objectIndex,int index)
{
	this->dataManipulator->EnterIntoChild(objectIndex);
	const QPointF t=this->dataManipulator->RControlPointAt(index);
	this->dataManipulator->EscapeToParent();
	return t;
}
centralController::centralController():QObject()
{
    this->currentEditIndex=new QVector<int>();
    this->dataManipulator=new DataManipulator();
    //this->fileManipulator=new IFileManipulator();
    this->xmlManager=new XMLManager();
    this->translator=new Translator();
    //this->currentContainerNodePath.path=new QVector<int>();
	QVector<int>t;
	this->currentContainerNodePath=t;
	this->UndoStack=new QUndoStack();
}
centralController::~centralController()
{
	//
	delete currentEditIndex;
	delete dataManipulator;
	delete xmlManager;
	delete UndoStack;
}
QVector<int> centralController::ObjectIndexUnderPointAt(QPointF pt)
{
	return this->dataManipulator->ChildrenUnderPointAt(pt);
}
const DisplayNode* centralController::GetObjectByIndex(int index)
{
	if(index==-1)
		return this->dataManipulator->CurrentPt();
	return this->dataManipulator->ChildPtAt(index);
}
QImage centralController::GetObjectImageByIndex(int index)
{
	return this->dataManipulator->ChildImageAt(index);
}
eNodeType centralController::GetNodeType(int index)
{
	eNodeType t;
	if(index==-1)
	{
		t=this->dataManipulator->CurrentNodeType();
		return t;
	}
	 this->dataManipulator->EnterIntoChild(index);
	  t=this->dataManipulator->CurrentNodeType();
	 this->dataManipulator->EscapeToParent();
	 return t;
}
int centralController::NumberOfObjects()
{
	 return this->dataManipulator->ChildrenCount();
}
int centralController::PointIndexAt(int objectIndex,double x,double y)
{
	this->dataManipulator->EnterIntoChild(objectIndex);
	int i=this->dataManipulator->PointIndexOf(x,y);
	this->dataManipulator->EscapeToParent();
	return i==-1?-1:i/3;
}
void centralController::receiveMessage(Message* msg)
{
	MessageType t=msg->returnType();
    switch(t){
    case createNewProjectMessage:
		{
			NewProjectArgs a=msg->getNewProjectArgs();
            this->dataManipulator->CreateProject(a.name,a.width,a.height,a.bkcolor,a.fps);
            break;
		}
    case selectContainerMessage:
		{ 
			switch(((SelectContainerMessage*)msg)->messageType)
			{
			case 0:
				{
					this->currentContainerNodePath.path=msg->getSelectContainerNodePath().path;
			        nodePath np=msg->getSelectContainerNodePath();
                    this->dataManipulator->ToRoot();
                    for(int i=0;i!=np.path.count();i++){
						this->dataManipulator->EnterIntoChild(np.path[i]);}
					break;
				}
			case 1:
				{
					this->currentContainerNodePath.path.pop_back();
				    this->dataManipulator->ToRoot();
				    for(int i=0;i!=this->currentContainerNodePath.path.count();i++){
					    this->dataManipulator->EnterIntoChild(this->currentContainerNodePath.path[i]);}
				    break;
				}
			case 2:
			   {
				    this->currentContainerNodePath.path.push_back(((SelectContainerMessage*)msg)->index);
				    this->dataManipulator->ToRoot();
				    for(int i=0;i!=this->currentContainerNodePath.path.count();i++){
					    this->dataManipulator->EnterIntoChild(this->currentContainerNodePath.path[i]);}
				    break;
			   }
			default:
				break;
			}
			break;
		}
		
    case selectObjectsMessage:
		{
			SelectObjectsArgs arg=msg->getSelectObjectsArgs();
			for (int i=0;i<arg.selectedIndex.count();i++)
			{
				if(this->currentEditIndex->indexOf(arg.selectedIndex[i])==-1)
					this->currentEditIndex->push_back(arg.selectedIndex[i]);
			}
			break;
		}
	case cancleCurrentEditObjectMessage:
		{
			this->currentEditIndex->clear();
			break;
		}
    case newNodeMessage:
		{
			NewNodeArgs args=msg->getNewNodeArgs();
		    if(args.argsType==4)
				args.parentPath=this->currentContainerNodePath;
			QUndoCommand* qc=new addNewNodeCommand(this->currentContainerNodePath,args,this->dataManipulator);
			this->UndoStack->push(qc);
			emit this->refreshTree(this->currentContainerNodePath);
			break;
		}
    case setPropertyValueMessage:
       { 
		   SetArgs setargs=msg->getSetArgs();
		   QUndoCommand* mc=new MacroCommand(); 
           //QVector<QUndoCommand*> cstack;
		   for(int i=0;i!=this->currentEditIndex->count();i++)
		   {
			   nodePath tmpp=this->currentContainerNodePath;
			   tmpp.path.push_back(currentEditIndex->at(i));
			   ((MacroCommand*)mc)->commands.push_back((QUndoCommand*)new setPropertyCommand(tmpp,setargs,this->dataManipulator));
		   }
           //this->UndoStack->beginMacro("a set of commands");
           //for(int i=0;i!=cstack.count();i++)
           this->UndoStack->push(mc);
           //this->UndoStack->endMacro();
		   break;
	   }
    case deleteNodeMessage:
		{
			int type=((DeleteNodeMessage*)(msg))->type;
			if(type==1)
			{
				((DeleteNodeMessage*)(msg))->deletePath=this->currentContainerNodePath;
				((DeleteNodeMessage*)(msg))->deletePath.path.push_back(((DeleteNodeMessage*)(msg))->index);
			}
			nodePath nodep=msg->getDeleteNodePath();
            QUndoCommand* o=new deleteNodeCommand(nodep,dataManipulator);
            this->UndoStack->push(o);
			emit this->refreshTree(this->currentContainerNodePath);
		    break;
		}
	case saveMessage:
		{
			QString path=msg->getSavePath();
            ContainerNode* root1;
            dataManipulator->ToRoot();
            root1=(ContainerNode*)(dataManipulator->CurrentPt());
		    this->xmlManager->OutputXML(this->dataManipulator->ScenePt()->name,path,root1,this->dataManipulator->ScenePt());
			this->xmlManager->OutputXML(this->dataManipulator->ScenePt()->name,path,root1);
		    break;
		}
	case undoMessage:
		{
			this->UndoStack->undo();
			break;
		}
	case redoMessage:
		{
			this->UndoStack->redo();
			break;
		}

    case generateJsMessage:
		{
			QString path2=msg->getJsPath();
		    this->translator->Clear();
		    this->translator->Initialize(this->dataManipulator->ScenePt());
		    this->dataManipulator->ToRoot();
		    this->translator->parseRootNode((ContainerNode*)this->dataManipulator->CurrentPt());
		    this->translator->Output(path2);
		    break;
		}
	case openProjectMessage:
		{
			OpenProjectArgs openArgs=msg->getOpenArgs();
		    MovieClipNode* movie;
		    SceneNode* snode;
		    this->xmlManager->LoadCBP(openArgs.openPath,openArgs.openName,movie,snode);
		    this->dataManipulator->LoadProject(snode,movie);
		    this->dataManipulator->Update();
		    break;
		}
	case closeProjectMessage:
		{
			this->dataManipulator->CloseProject();
			break;
		}
	case setStaticPropertyMessage:
		{
			SetStaticProperArgs ssetargs=msg->getStaticSetArgs();
            //QVector<QUndoCommand*> cstack;
			QUndoCommand* mc1=new MacroCommand();
            for(int i=0;i!=this->currentEditIndex->count();i++)
			{
				nodePath tmpp=this->currentContainerNodePath;
			    tmpp.path.push_back(currentEditIndex->at(i));
				((MacroCommand*)mc1)->commands.push_back((QUndoCommand*)new setStaticPropertyCommand(tmpp,ssetargs,this->dataManipulator));
			}
            //this->UndoStack->beginMacro("a set of commands");
            //for(int i=0;i!=cstack.count();i++)
            this->UndoStack->push(mc1);
            //this->UndoStack->endMacro();
		    break;
		}
	case nodeConvertMessage:
		{
			NodeType t=msg->getConvertType();
			//QVector<QUndoCommand*> cstack;
			QUndoCommand* mc2=new MacroCommand();
            for(int i=0;i!=this->currentEditIndex->count();i++)
			{
				nodePath tmpp=this->currentContainerNodePath;
			    tmpp.path.push_back(currentEditIndex->at(i));
				((MacroCommand*)(mc2))->commands.push_back((QUndoCommand*)new nodeConvertCommand(tmpp,t,this->dataManipulator));
			}
            //this->UndoStack->beginMacro("a set of commands");
           // for(int i=0;i!=cstack.count();i++)
            this->UndoStack->push(mc2);
            //this->UndoStack->endMacro();
		    break;
		}
	case swapLayerMessage:
		{
			int ori=this->currentEditIndex->at(0);
			int dest=msg->returnDestLayerIndex();
			QUndoCommand* sm=new swapLayerCommand(this->currentContainerNodePath,ori,dest,this->dataManipulator);
			this->UndoStack->push(sm);
			break;
		}
	case addPointMessage:
		{
			nodePath tmp=this->currentContainerNodePath;
			tmp.path.push_back(this->currentEditIndex->at(0));
			QUndoCommand* ac=new addCurvePointCommand(tmp,msg->getAddPointArgs(),this->dataManipulator);
			this->UndoStack->push(ac);
			break;
		}
	case deletePointMessage:
		{
			nodePath tmp=this->currentContainerNodePath;
			tmp.path.push_back(this->currentEditIndex->at(0));
			QUndoCommand* dpm=new deletePointCommand(tmp,msg->getDeletePointIndex(),this->dataManipulator);
			this->UndoStack->push(dpm);
			break;
		}
	case movePointMessage:
		{
			nodePath tmp=this->currentContainerNodePath;
			tmp.path.push_back(this->currentEditIndex->at(0));
			QUndoCommand* mpm=new moveCurvePointCommand(tmp,msg->getMovePointArgs(),this->dataManipulator);
			this->UndoStack->push(mpm);

			break;
		}
	case changePointTypeMessage:
		{
			nodePath tmp=this->currentContainerNodePath;
			tmp.path.push_back(this->currentEditIndex->at(0));
			QUndoCommand* cpm=new changePointTypeCommand(tmp,msg->getChangePointTypeArgs(),this->dataManipulator);
			this->UndoStack->push(cpm);
			break;
		}
	case setGradientMessage:
		{
			nodePath tmp=this->currentContainerNodePath;
			tmp.path.push_back(this->currentEditIndex->at(0));
			QUndoCommand* sgc=new setGradientCommand(tmp,msg->getGradientArgs(),this->dataManipulator);
			this->UndoStack->push(sgc);
			break;
		}
	default:
		break;
		
	}
	this->dataManipulator->ToRoot();
	this->dataManipulator->Update();
	this->dataManipulator->ToRoot();
	for(int i=0;i!=this->currentContainerNodePath.path.count();i++)
        {
			this->dataManipulator->EnterIntoChild(this->currentContainerNodePath.path[i]);
        }
	delete msg;
	

}
double centralController::ImageOffsetX(int index)
{
	const DisplayNode* pt=this->dataManipulator->ChildPtAt(index);
	return pt->CacheOffsetX();

}
double centralController::ImageOffsetY(int index)
{
	const DisplayNode* pt=this->dataManipulator->ChildPtAt(index);
	return pt->CacheOffsetY();
}
QImage centralController::GetCurrentContainerImage()
{
	return this->dataManipulator->CurrentImage();
}
double centralController::CurrentContainerImageOffX()
{
	 const DisplayNode* pt=this->dataManipulator->CurrentPt();
	 return pt->CacheOffsetX();

}
double centralController::CurrentContainerImageOffY()
{
	 
	 const DisplayNode* pt=this->dataManipulator->CurrentPt();
	 return pt->CacheOffsetY();

}
double centralController::GetValueByIndex(int index,propertyType type,int time)
{
	this->dataManipulator->EnterIntoChild(index);
	double value=this->dataManipulator->GetNodeProperty(type,time);
	this->dataManipulator->EscapeToParent();
	return value;
}
Ease::EaseType	centralController::GetNodePropertyEaseByIndex(int index,propertyType type,int time)
{
	this->dataManipulator->EnterIntoChild(index);
	Ease::EaseType value=this->dataManipulator->GetNodePropertyEase(type,time);
	this->dataManipulator->EscapeToParent();
	return value;
}
QVector<int> centralController::GetPropertyKeyFramesTime(propertyType type,int index)
{
	QVector<int>tmp;
	tmp=this->dataManipulator->GetKeyFrames(((int)(type)),index);
	return tmp;
}
QString centralController::getNodeName(int index)
{
	QString name;
	if(index==-1)
	{
		name=this->dataManipulator->CurrentNodeName();
	}
	else
	{
		this->dataManipulator->EnterIntoChild(index);
		name=this->dataManipulator->CurrentNodeName();
	     this->dataManipulator->EscapeToParent();
	}
	return name;
}
void centralController::removeKeyFrames(propertyType type,int time)

{
	this->dataManipulator->RemoveKeyFrames(((int)(type)),time,this->currentEditIndex->at(0));
}


bool  centralController::addNode(int index)
{
	QString fileName=QFileDialog::getOpenFileName(0, tr("Open Image"),"", tr("Images (*.png *.xpm *.jpg)"));
	if (!fileName.isEmpty()) 
	{
		
		int i=fileName.lastIndexOf(QChar('\\'));
		QString path=fileName.left(i+1);
		QString name=fileName.right(fileName.length()-i-1);
		MovieClipNode *node;
		this->xmlManager->LoadBLK(path, name, node);
		if (!node) 
		{
			QMessageBox::information(0, tr("Image Viewer"),
				tr("Cannot load %1.").arg(fileName));
			return false;
		}
		this->dataManipulator->AddNodeAt(node,index);
		return true;
	}
	return false;
}
int centralController::sceneW()
{
	return this->dataManipulator->ScenePt()->Width;
}
int centralController::sceneH()
{
	return this->dataManipulator->ScenePt()->Height;
}